#include "ii_pfs.h"
#include <omp.h>
#include <vector>
#include <memory>

using std::vector;

II_PFS::II_PFS(const PFS_Item& pfs_item,
	double time_limit, int neighbor_per_time, int retry_limit)
  : PFS_Calculator(pfs_item, time_limit),
	neighbor_per_time_(neighbor_per_time), retry_limit_(retry_limit) {}

PFS_Calculator::Answer II_PFS::Calculate() {
  InitResult();  

  double start_time = omp_get_wtime();
  while (omp_get_wtime() - start_time <= time_limit()) {
    II_Process(start_time);
  }

  return best_answer();
}


void II_PFS::II_Process(double start_time) {
  Solution solution = GetRandomSolution(); //65.2%, 9.4
  int score_now = Score(solution);
  PushAnswer(score_now, solution);

  Solution next_solution(0);
  while(omp_get_wtime() - start_time <= time_limit()) {
    next_solution.clear();

		for (int retry = 0 ;; ++retry) {
			FindBestNeighbor(solution, &score_now, &next_solution); 

			if (!next_solution.empty())
				break;
			else if (retry >= retry_limit())
				return;
		}

		SolutionGo(&solution, next_solution);
    PushAnswer(Score(solution), solution);
  }

}

void II_PFS::FindBestNeighbor(const Solution& solution,
		int* score_now, Solution* next_solution) {
	#pragma omp parallel for
	for (int i = 0 ; i < neighbor_per_time() ; ++i) {
		Solution neighbor = GetNeighbor(solution);
		int neighbor_score = Score(neighbor);

		if (neighbor_score > *score_now) {

			#pragma omp critical
			{
				if (neighbor_score > *score_now) {
					*score_now = neighbor_score;
					*next_solution = std::move(neighbor);
				}
			}

		}
	}
}